/*-------------------------------------------------------------------------
 *
 * mxactdesc.c
 *      rmgr descriptor routines for access/transam/multixact.c
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *      src/backend/access/rmgrdesc/mxactdesc.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/multixact.h"

static void
out_member(StringInfo buf, MultiXactMember *member)
{
    appendStringInfo(buf, "%u ", member->xid);
    switch (member->status)
    {
        case MultiXactStatusForKeyShare:
            appendStringInfoString(buf, "(keysh) ");
            break;
        case MultiXactStatusForShare:
            appendStringInfoString(buf, "(sh) ");
            break;
        case MultiXactStatusForNoKeyUpdate:
            appendStringInfoString(buf, "(fornokeyupd) ");
            break;
        case MultiXactStatusForUpdate:
            appendStringInfoString(buf, "(forupd) ");
            break;
        case MultiXactStatusNoKeyUpdate:
            appendStringInfoString(buf, "(nokeyupd) ");
            break;
        case MultiXactStatusUpdate:
            appendStringInfoString(buf, "(upd) ");
            break;
        default:
            appendStringInfoString(buf, "(unk) ");
            break;
    }
}

void
multixact_desc(StringInfo buf, XLogReaderState *record)
{
    char       *rec = XLogRecGetData(record);
    uint8        info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;

    if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE ||
        info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
    {
        int            pageno;

        memcpy(&pageno, rec, sizeof(int));
        appendStringInfo(buf, "%d", pageno);
    }
    else if (info == XLOG_MULTIXACT_CREATE_ID)
    {
        xl_multixact_create *xlrec = (xl_multixact_create *) rec;
        int            i;

        appendStringInfo(buf, "%u offset %u nmembers %d: ", xlrec->mid,
                         xlrec->moff, xlrec->nmembers);
        for (i = 0; i < xlrec->nmembers; i++)
            out_member(buf, &xlrec->members[i]);
    }
    else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
    {
        xl_multixact_truncate *xlrec = (xl_multixact_truncate *) rec;

        appendStringInfo(buf, "offsets [%u, %u), members [%u, %u)",
                         xlrec->startTruncOff, xlrec->endTruncOff,
                         xlrec->startTruncMemb, xlrec->endTruncMemb);
    }
}

const char *
multixact_identify(uint8 info)
{
    const char *id = NULL;

    switch (info & ~XLR_INFO_MASK)
    {
        case XLOG_MULTIXACT_ZERO_OFF_PAGE:
            id = "ZERO_OFF_PAGE";
            break;
        case XLOG_MULTIXACT_ZERO_MEM_PAGE:
            id = "ZERO_MEM_PAGE";
            break;
        case XLOG_MULTIXACT_CREATE_ID:
            id = "CREATE_ID";
            break;
        case XLOG_MULTIXACT_TRUNCATE_ID:
            id = "TRUNCATE_ID";
            break;
    }

    return id;
}
